package dao

import (
	"context"
	"gorm.io/gorm"
	"gorm.io/gorm/clause"
	"time"
)

var ErrRecordNotFound = gorm.ErrRecordNotFound

type InteractiveDAO interface {
	IncrReadCnt(ctx context.Context, biz string, bizId int64) error
	BatchIncrReadCnt(ctx context.Context, bizs []string, ids []int64) error
	InsertLikeInfo(ctx context.Context, biz string, bizId int64, uid int64) error
	DeleteLikeInfo(ctx context.Context, biz string, bizId int64, uid int64) error
	InsertCollectionBiz(ctx context.Context, collection UserCollectionBiz) error
	GetLikeInfo(ctx context.Context, biz string, bizId int64, uid int64) (UserLikeBiz, error)
	GetCollectionInfo(ctx context.Context, biz string, bizId int64, uid int64) (UserCollectionBiz, error)
	Get(ctx context.Context, biz string, bizId int64) (Interactive, error)
	InsertReadHistory(ctx context.Context, aid int64, uid int64) error
}

type GORMInteractiveDAO struct {
	db *gorm.DB
}

func NewGORMInteractiveDAO(db *gorm.DB) InteractiveDAO {
	return &GORMInteractiveDAO{
		db: db,
	}
}

func (dao *GORMInteractiveDAO) IncrReadCnt(ctx context.Context, biz string, id int64) error {
	now := time.Now().UnixMilli()
	return dao.db.WithContext(ctx).Clauses(clause.OnConflict{
		DoUpdates: clause.Assignments(map[string]interface{}{
			"read_cnt":    gorm.Expr("`read_cnt`+1"),
			"update_time": now,
		}),
	}).Create(&Interactive{
		Biz:        biz,
		BizId:      id,
		ReadCnt:    1,
		CreatTime:  now,
		UpdateTime: now,
	}).Error
}

func (dao *GORMInteractiveDAO) BatchIncrReadCnt(ctx context.Context, bizs []string, ids []int64) error {
	err := dao.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
		txDAO := NewGORMInteractiveDAO(tx)
		for i := range bizs {
			err := txDAO.IncrReadCnt(ctx, bizs[i], ids[i])
			if err != nil {
				return err
			}
		}
		return nil
	})
	return err
}

func (dao *GORMInteractiveDAO) InsertLikeInfo(ctx context.Context, biz string, bizId int64, uid int64) error {
	// 同时记录点赞和更新点赞数
	// 点赞：谁给什么点了赞
	now := time.Now().UnixMilli()
	// 记录点赞
	return dao.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
		err := tx.Clauses(clause.OnConflict{
			DoUpdates: clause.Assignments(map[string]interface{}{
				"update_time": now,
				"status":      1,
			}),
		}).Create(&UserLikeBiz{
			Biz:        biz,
			BizId:      bizId,
			Uid:        uid,
			Status:     1,
			CreateTime: now,
			UpdateTime: now,
		}).Error
		if err != nil {
			return err
		}
		return tx.WithContext(ctx).Clauses(clause.OnConflict{
			DoUpdates: clause.Assignments(map[string]interface{}{
				"like_cnt":    gorm.Expr("`like_cnt`+1"),
				"update_time": now,
			}),
		}).Create(&Interactive{
			Biz:        biz,
			BizId:      bizId,
			LikeCnt:    1,
			CreatTime:  now,
			UpdateTime: now,
		}).Error
	})
}

func (dao *GORMInteractiveDAO) DeleteLikeInfo(ctx context.Context, biz string, bizId int64, uid int64) error {
	now := time.Now().UnixMilli()
	return dao.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
		// 两个操作： 软删除 + 减少点赞量
		err := tx.Model(&UserLikeBiz{}).Where("biz=? AND biz_id=? AND uid=?", biz, bizId, uid).
			Updates(map[string]interface{}{
				"update_time": now,
				"status":      2,
			}).Error
		if err != nil {
			return err
		}
		return tx.Model(&Interactive{}).Where("biz=? AND biz_id=?", biz, bizId).
			Updates(map[string]interface{}{
				"update_time": now,
				"like_cnt":    gorm.Expr("`like_cnt`-1"),
			}).Error
	})
}

// 插入收藏记录，并更新计数
func (dao *GORMInteractiveDAO) InsertCollectionBiz(ctx context.Context, colBiz UserCollectionBiz) error {
	now := time.Now().UnixMilli()
	colBiz.CreateTime = now
	colBiz.UpdateTime = now
	return dao.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
		err := dao.db.WithContext(ctx).Create(&colBiz).Error
		if err != nil {
			return err
		}
		return tx.Clauses(clause.OnConflict{
			DoUpdates: clause.Assignments(map[string]interface{}{
				"collect_cnt": gorm.Expr("`collect_cnt`+1"),
				"update_time": now,
			}),
		}).Create(&Interactive{
			CollectCnt: 1,
			CreatTime:  now,
			UpdateTime: now,
			Biz:        colBiz.Biz,
			BizId:      colBiz.BizId,
		}).Error
	})
}

func (dao *GORMInteractiveDAO) GetLikeInfo(ctx context.Context, biz string, bizId int64, uid int64) (UserLikeBiz, error) {
	var res UserLikeBiz
	err := dao.db.WithContext(ctx).
		Where("biz=? AND biz_id=? AND uid=? and status=?",
			biz, bizId, uid, 1).First(&res).Error
	return res, err
}

func (dao *GORMInteractiveDAO) GetCollectionInfo(ctx context.Context, biz string, bizId int64, uid int64) (UserCollectionBiz, error) {
	var res UserCollectionBiz
	err := dao.db.WithContext(ctx).
		Where("biz=? AND biz_id=? AND uid=?",
			biz, bizId, uid).First(&res).Error
	return res, err
}

func (dao *GORMInteractiveDAO) Get(ctx context.Context, biz string, bizId int64) (Interactive, error) {
	var res Interactive
	err := dao.db.WithContext(ctx).
		Where("biz=? AND biz_id=?",
			biz, bizId).First(&res).Error
	return res, err
}

// 阅读记录，待完善
func (dao *GORMInteractiveDAO) InsertReadHistory(ctx context.Context, aid int64, uid int64) error {
	//now := time.Now().UnixMilli()
	return nil
}

type Interactive struct {
	Id int64 `gorm:"primaryKey, autoIncrement"`
	// 业务标识符，创建联合唯一索引
	BizId int64  `gorm:"uniqueIndex:biz_id_type"`
	Biz   string `gorm:"uniqueIndex:biz_id_type;type:varchar(128)"`
	// 阅读计数
	ReadCnt    int64
	LikeCnt    int64
	CollectCnt int64
	CreatTime  int64
	UpdateTime int64
}

type UserLikeBiz struct {
	Id int64 `gorm:"primaryKey, autoIncrement"`
	// 创建联合索引
	Biz        string `gorm:"uniqueIndex:uid_biz_id_type;type:varchar(128)"`
	BizId      int64  `gorm:"uniqueIndex:uid_biz_id_type"`
	Uid        int64  `gorm:"uniqueIndex:uid_biz_id_type"`
	CreateTime int64
	UpdateTime int64
	// 存储状态，软删除；1-有效；2-删除
	Status uint8
}

type UserCollectionBiz struct {
	Cid        int64
	Biz        string
	BizId      int64
	Uid        int64
	CreateTime int64
	UpdateTime int64
}

// 阅读记录，待完善
type UserReadHistory struct {
	Id         int64
	Biz        string
	BizId      int64
	Uid        int64
	CreateTime int64
	UpdateTime int64
}
